#ifndef _VARIABLE_CONTEXT_HEADER
#define _VARIABLE_CONTEXT_HEADER

#include "GenericData.h"
#include "GenericVariable.h"
#include "Selection.h"
#include "ExpandableList.h"

/**
 * VariableContext.h
 *
 * Description: 
 * An VariableContext object is a context for variables.  Within the larger MonkeyWorks 
 * framework, variables are made up of two parts, a lexical element (analogous to the
 * name of a C variable, e.g. "i"), and an actual value (e.g. "4").  A given lexical
 * token can have the value that it is associated with change (e.g. "i = 4; i = 5"),
 * without changing the lexical token itself (i.e. "i").  One additional wrinkle is that
 * a given token (e.g. "i") can mean different things depending on context.  For instance,
 * it we call a function, a local declaration of "i" will shadow any global definition of
 * a variable of the same name.  Such shadowing is particularly handy when defining an
 * experiment, since it is often natural to define a variable for all branches of a
 * hierarchy below a certain point.  Thus, it might be convenient to defined a default
 * value of "fixation_location" to be [0,0] for the experiment as a whole, and then 
 * just override it with different values only for those trials (and their sub-states) 
 * that need it to be something different (e.g. for calibration trials).  When those 
 * trials are done, we'd like fixation_location to return to whatever it used to be, just
 * as the meaning of "i" returns to it's global meaning after you return from a function.
 * If you don't see the utility of this, just trust me for now.  Example experiments will
 * demonstrate why this is good.
 *
 * VariableContexts  either define what a variables
 * value is within the present context (each state has it's own VariableContext object), or they
 * point back through the hierarchy to wherever the value was last defined.
 *
 * This object used to be called a "mTrialInfo," so references to "TrialInfos" may occur
 * throughout the comments in this project
 *
 * History:
 * ??/??/?? ??? - Created.
 * 04/14/04 PAJ - added accessor methods to return list pointers for simple 
 *                list traversal used in Experiment Browser window.
 * Paul Jankunas on 1/24/06 - Adding virtual destructor.
 */	
enum  Transparency{ M_TRANSPARENT, M_OPAQUE };

// The base trial info object, containing user defined variables which are needed to run trials

class VariableContext : public Lockable{

	protected:

		ExpandableList<Data> *data; // a list of pointers to data
		ExpandableList<Transparency> *transparency; // a list of flags whether the object
                                                              // is actually defined here or is inherited
                                                              
	public:
	
		VariableContext();
		VariableContext(int nfields);	     // just create an empty structure
		VariableContext(VariableContext *ownersinfo);  // point through to a parent

		void inheritFrom(VariableContext *info_to_inherit);  // inherit from a parent, unless already 
                                                                // defined opaque
		virtual ~VariableContext();
        
		virtual Transparency getTransparency(Variable *param);
		virtual Transparency getTransparency(int i);
                
		Data *getDataPointer(Variable *param); // this gets the pointer stored in the data list
		Data *getDataPointer(int index); // this gets the pointer stored in the data list

		void setDataPointer(Variable *param, Data *dp);  // set the pointer manually
		void setDataPointer(int index, Data *dp);  // set the pointer manually
                                		
		int getNFields(); // how many fields?
		
		Data get(Variable *param);
                
		void set(Variable *param, Data *newdata);
		void set(Variable *param, const Data& newdata);
		void set(Variable *param, long newdata);
		void set(Variable *param, double newdata);
		void set(Variable *param, bool newdata);

		void inc(Variable *index);
                
		GenericDataType getDataType(Variable *index);
                
		/**
		 * getDataList - returns a pointer to the ExpandableList of
		 * Data items.
		 */
		ExpandableList<Data> * getDataList();
		
		/**
		 * getTransparencyList - returns a pointer to the 
		 * ExpandableList of Transparency items.
		 */
		ExpandableList<Transparency> * getTransparencyList();

		
		/*
		template <class T>
		void bindVariable(Variableparam, T *variable_to_bind){
			Data *newdata;
	
			if(is_basic_type(T)){
					newdata = new Data(variable_to_bind);
					newdata->setData(defaultvalue);
			} else {
					throw("Not implemented");
					//newdata = new Data();
					//newdata->bindGenericObject<T>(variable_to_bind);
			}
			
			data->addElement(param->getIndex(), newdata);
			transparency->addElement(param->getIndex(), M_OPAQUE);
}
		
		template <class T>
		void bindFunction(Variableparam, T (*getptr)()){
			Data *newdata = new Data(M_BOUND_FUNCTION_POINTER, getptr, setptr);
			newdata->setData(defaultvalue);
			data->addElement(param->getIndex(), newdata);
			transparency->addElement(param->getIndex(), M_OPAQUE);
		}*/

};






                /*  
                char *getString(int index);
		long getInt(int index);
		double getFloat(int index);
		bool getBool(int index);
                */
		

		/*
                void setInt(int ind, long value);
		void setFloat(int ind, double value);
		void setBool(int ind, bool value);
                */


                
                /* TODO: fix this
		template <class T>
		void setObjectOpaque(int ind, T newdata){
			data->addElement(ind, newdata);
		}
                */
                /*
		template <class T>	
		void setObject(int ind, T newdata){
			
			Data *temp = (*data)[resolve(ind)];
			
			int object_type = temp->getObjectType();
			if(object_type == M_GENERIC_OBJECT_DATA){
				GenericObjectData *genobj;
	
				if(!(genobj = dynamic_cast<GenericObjectData<T> *>((temp->)))){   // C++ black arts!
					throw("Error: attempt to cast to an incorrect generic object data type!");
				}
				
				genobj->setData(newdata);
			}
						
			if(object_type == M_BOUND_GENERIC_OBJECT){
				BoundGenericObject *boundgen;

				if(!(boundgen = dynamic_cast<BoundGenericObject<T> *>(temp->))){ // C++ black arts here.
					throw("Error: attempt to cast to an incorrect bound generic object data type!");
				}
				
				boundgen->setData(newdata);
			}
			
			throw("Error: failed to return a generic object in a getObject() call");
		}
                */


#endif

